package cn.com.digitalnet.ad.base;

import static org.assertj.core.api.Assertions.*;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Map;

import javax.servlet.ServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.ui.Model;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.springside.modules.web.Servlets;

import cn.com.digitalnet.ad.util.FileUploader;
import cn.com.digitalnet.ad.util.Holder;

import com.google.common.collect.Maps;

/**
 * 标准增删改查Controller
 * @author qidafang
 */
public abstract class CrudController<E extends IdEntity> {

	@Autowired protected FileUploader uploader;
	
	protected abstract CrudService<E> service();
	
	protected abstract String english();
	
	protected abstract String chinese();

	protected abstract String parentMenu();

	//key:翻页字段名称,value:翻页字段中文
	protected Map<String, String> sortTypes = Maps.newLinkedHashMap();
	
	protected Sort getSort(String sortType, String sortDire){
		Direction dire = Direction.ASC;
		if("asc".equalsIgnoreCase(sortDire)){
			dire = Direction.ASC;
		}else{
			dire = Direction.DESC;
		}
		
		if(sortTypes.containsKey(sortType)){
			if(sortType.equals("id")){
				return new Sort(Direction.DESC, "id");
			}else{
				return new Sort(dire, sortType);
			}
		}else{
			return new Sort(Direction.DESC, "id");
		}
	}
	
	/**
	 * 标准分页列表
	 * @author qidafang
	 */
	protected String standardList(int pageNumber, int pageSize, String sortType, String sortDire, Model model,
			ServletRequest request) {
		//do
		Map<String, Object> searchParams = Servlets.getParametersStartingWith(request, "search_");
		addSearchParam(searchParams);
		Page<E> page = service().page(searchParams, new PageRequest(pageNumber - 1, pageSize, getSort(sortType, sortDire)));
		doWithPage(page, model);
		//model
		model.addAttribute("parentMenu", parentMenu());
		model.addAttribute("menu", english());
		model.addAttribute(english() + "s", page);
		model.addAttribute("sortType", sortType);
		model.addAttribute("sortTypes", sortTypes);
		model.addAttribute("sortDire", sortDire);
		/*将搜索条件编码成字符串，用于排序，分页的URL*/
		model.addAttribute("searchParams", Servlets.encodeParameterStringWithPrefix(searchParams, "search_"));
		//view
		return english() + "List";
	}
	
	protected void addSearchParam(Map<String, Object> searchParams){
		//...
	}
	
	/**
	 * 获得翻页数据后执行动作的扩展点
	 * @author qidafang
	 */
	protected void doWithPage(Page<E> page, Model model){
	}

	/**
	 * 标准新建表单
	 * @author qidafang
	 */
	protected String standardCreateForm(Model model) {
		//model
		model.addAttribute("parentMenu", parentMenu());
		model.addAttribute("menu", english());
		model.addAttribute("action", "create");
		//view
		return english() + "Form";
	}

	/**
	 * 标准新建事件
	 * @author qidafang
	 */
	protected String standardCreate(E e, RedirectAttributes redirectAttributes) {
		//do
		service().save(e);
		//model
		redirectAttributes.addFlashAttribute("message", "添加" + chinese() + "成功");
		//view
		return "redirect:/" + english();
	}

	/**
	 * 标准查看
	 * @author qidafang
	 */
	protected String standardView(Long id, Model model) {
		//model
		model.addAttribute("parentMenu", parentMenu());
		model.addAttribute("menu", english());
		model.addAttribute("action", "view");
		E e = findEntityForUpdateForm(id);
		doAfterFindEntityForUpdateForm(e,model);
		//确保存在要更新的实体并有权限
		assertNotNull(e);
		model.addAttribute(english(), e);
		//view
		return english() + "Form";
	}
	
	/**
	 * 标准修改表单
	 * @author qidafang
	 */
	protected String standardUpdateForm(Long id, Model model) {
		//model
		model.addAttribute("parentMenu", parentMenu());
		model.addAttribute("menu", english());
		model.addAttribute("action", "update");
		E e = findEntityForUpdateForm(id);
		doAfterFindEntityForUpdateForm(e,model);
		//确保存在要更新的实体并有权限
		assertNotNull(e);
		model.addAttribute(english(), e);
		//view
		return english() + "Form";
	}
	
	/**
	 * 获得要修改的实体，被standardUpdateForm方法使用，可由子类覆盖
	 * @author qidafang
	 */
	protected E findEntityForUpdateForm(Long id){
		E e = service().findOne(id);
		return e;
	}
	
	/**
	 * 获得要修改的实体之后做些事情的扩展点
	 * @author qidafang
	 */
	protected void doAfterFindEntityForUpdateForm(E e,Model model){
		// TODO Auto-generated method stub
		
	}

	/**
	 * 标准修改事件
	 * @author qidafang
	 */
	protected String standardUpdate(E e, RedirectAttributes redirectAttributes) {
		//确保存在要更新的实体并有权限
		assertNotNull(e);
		//do
		service().update(e);
		//model
		redirectAttributes.addFlashAttribute("message", "更新" + chinese() + "成功");
		//view
		return "redirect:/" + english();
	}

	/**
	 * 标准删除事件
	 * @author qidafang
	 */
	protected String standardDelete(Long id, RedirectAttributes redirectAttributes) {
		//确保存在要删除的实体并有权限
		assertNotNull(service().findOne(id));
		//do
		service().delete(id);
		//model
		redirectAttributes.addFlashAttribute("message", "删除"+chinese()+"成功");
		//view
		return "redirect:/" + english();
	}
	
	/**
	 * 标准提交事件
	 * @author qidafang
	 */
	protected String standardSubmit(Long id, RedirectAttributes redirectAttributes){
		//确保存在要提交的实体并有权限
		assertNotNull(service().findOne(id));
		//do
		service().submit(id);
		//model
		redirectAttributes.addFlashAttribute("message", "发布"+chinese()+"成功");
		//view
		return "redirect:/" + english();
	}

	/**
	 * 标准预绑定实体（修改事件之前使用）
	 * @author qidafang
	 */
	protected void standardGetEntity(Long id, Model model) {
		if (id != -1) {
			E e = service().findOne(id);
			//确保存在要更新的实体并有权限
			assertNotNull(e);
			model.addAttribute("_entity_", e);
		}
	}

	/**
	 * 断言要操作的实体存在且操作者有权限
	 * 可以扩展此方法来记录恶意操作者
	 * @author qidafang
	 */
	protected void assertNotNull(E e){
		//确保存在要操作的实体并有权限
		assertThat(e).isNotNull();
	}

	public String standardImportData(Model model){
		//model
		model.addAttribute("parentMenu", parentMenu());
		model.addAttribute("menu", english());
		model.addAttribute("english", english());
		//view
		return "importForm";
	}

	public String standardDoImport(MultipartFile multipartFile, RedirectAttributes redirectAttributes){

		File file = uploader.doImport(multipartFile);
		Workbook workbook = null;
		String ext = StringUtils.substringAfterLast(multipartFile.getOriginalFilename(), ".");
		try{
			InputStream in = new FileInputStream(file);
			
	        if (ext.equalsIgnoreCase("xls")) {
	            workbook= new HSSFWorkbook(in);
	        }else if (ext.equalsIgnoreCase("xlsx")) {
	        	workbook= new XSSFWorkbook(in);
	        }
	        
			service().importExcel(workbook);
			
			//model
			redirectAttributes.addFlashAttribute("message", "导入" + chinese() + "成功");
		}catch(Exception e){
			//model
			redirectAttributes.addFlashAttribute("messageType", "danger");
			redirectAttributes.addFlashAttribute("message", "导入" + chinese() + "失败，" + Holder.errors.get().toHTML());
			e.printStackTrace();
		}
		
		//view
		return "redirect:/" + english();
	}

}
